package org.theSeed.fileConfig.config;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import org.theSeed.base.exp.ServiceExp;
import org.theSeed.base.pojo.sysEnum.SysCode;
import org.theSeed.fileConfig.pojo.prop.SeedFileUploadProp;
import org.theSeed.fileContract.contract.FileContract;
import org.theSeed.fileContract.contract.UploadFileRecorder;
import org.theSeed.fileContract.exp.FileUploadExp;
import org.theSeed.fileContract.paramEncoder.SeedFileParamEncoder;
import org.theSeed.fileContract.pojo.dto.*;
import org.theSeed.fileContract.pojo.prop.FileConfigProp;
import org.theSeed.fileContract.pojo.vo.*;

import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class SeedFileHolder {
    public SeedFileHolder(SeedFileUploadProp seedFileUploadProp, Map<String, FileConfigProp> fileConfigPropMap, Map<String, FileContract> fileContractMap, SeedFileParamEncoder seedFileParamEncoder, UploadFileRecorder uploadFileRecorder){
        if (ObjectUtil.isNotNull(seedFileUploadProp) || ObjectUtil.isNotNull(fileContractMap) || ObjectUtil.isNotNull(fileConfigPropMap) || ObjectUtil.isNotNull(seedFileParamEncoder) || ObjectUtil.isNotNull(uploadFileRecorder)){
            this.seedFileUploadProp = seedFileUploadProp;
            this.fileContractMap = fileContractMap;
            this.fileConfigPropMap = fileConfigPropMap;
            this.seedFileParamEncoder = seedFileParamEncoder;
            this.uploadFileRecorder = uploadFileRecorder;
        }
    }

    protected SeedFileUploadProp seedFileUploadProp;

    /**
     * 所有文件上传实例
     */
    protected Map<String, FileContract> fileContractMap;

    /**
     * 所有文件上传配置
     */
    protected Map<String, FileConfigProp> fileConfigPropMap;

    /**
     * 加密工具
     */
    private SeedFileParamEncoder seedFileParamEncoder;

    /**
     * 文件上传记录者
     */
    private UploadFileRecorder uploadFileRecorder;

    /**
     * 获取适配的上传的实例
     * @param resourceUrl
     * @return
     */
    protected FileContract getAdapterFileContract(String resourceUrl){
        return fileContractMap.values().stream().filter(ele -> ele.jurgeInstance(resourceUrl)).findFirst().orElse(null);
    }

    /**
     * 获取请求地址适配详细信息
     * @param resourceUrl
     * @return
     */
    protected ResourceUrlDividVo getResourceUrlDividVo(String resourceUrl){
        FileContract adapterFileContract = getAdapterFileContract(resourceUrl);
        if (ObjectUtil.isNotNull(adapterFileContract)){
            ResourceUrlDividVo resourceUrlDividVo = adapterFileContract.sliceRequestUrl(resourceUrl);
            if (ObjectUtil.isNotNull(resourceUrlDividVo)){
                resourceUrlDividVo.checkParam();
                return resourceUrlDividVo;
            }
        }
        throw new FileUploadExp("文件获取失败:不存在对应的oss");
    }

    /**
     * 通过实例名称获取上传实例
     * @param contractTypeInstance
     * @return
     */
    protected FileContract getFileContractByInstanceName(String contractTypeInstance) {
        FileContract defaultContract;
        if (ObjectUtil.isNotNull(contractTypeInstance)){
            defaultContract = fileContractMap.get(contractTypeInstance);
            if (ObjectUtil.isNull(defaultContract))
                throw new FileUploadExp("文件上传失败:上传已实例关闭");
        }
        else{
            defaultContract = fileContractMap.get(seedFileUploadProp.getActiveInstanceName());
        }
        return defaultContract;
    }

    /**
     * 获取文件
     * @return
     */
    public InputStream getFile(SeedGetFileProxyDto seedGetFileProxyDto){
        if (ObjectUtil.isEmpty(seedGetFileProxyDto.getResourceUrl())){
            throw new FileUploadExp("文件上传失败:resourceUrl不能为空");
        }
        ResourceUrlDividVo resourceUrlDividVo = getResourceUrlDividVo(seedGetFileProxyDto.getResourceUrl());
        SeedGetFileDto seedGetFileDto = new SeedGetFileDto();
        seedGetFileDto.setResourceId(resourceUrlDividVo.getResourceId());
        return resourceUrlDividVo.getFileContract().getFile(seedGetFileDto);
    }

    /**
     * 文件上传
     */
    public SeedUploadFileProxyVo uploadFile(SeedUploadFileDto seedUploadFileDto){
        FileContract defaultContract = getFileContractByInstanceName(seedUploadFileDto.getContractTypeInstance());
        if (ObjectUtil.isNull(seedUploadFileDto.getIs())){
            throw new FileUploadExp("文件上传失败:is不能为空");
        }
        SeedUploadFileVo seedUploadFileVo = defaultContract.uploadFile(seedUploadFileDto);
        uploadFileRecorder.addUploadInfo(new RecordFileUniInfoDto(defaultContract.getContractTypeInstance(),defaultContract.getContractType(),seedUploadFileVo.getResourceId()));
        SeedUploadFileProxyVo seedUploadFileProxyVo = BeanUtil.copyProperties(seedUploadFileVo, SeedUploadFileProxyVo.class);
        seedUploadFileProxyVo.setContractType(defaultContract.getContractType());
        seedUploadFileProxyVo.setContractTypeInstance(defaultContract.getContractTypeInstance());
        return seedUploadFileProxyVo;
    }

    /**
     * 文件上传更新
     */
    public SeedUploadFileProxyVo updateFile(SeedUpdateFileProxyDto seedUpdateFileProxyDto){
        if (ObjectUtil.isEmpty(seedUpdateFileProxyDto.getResourceUrl())){
            throw new FileUploadExp("文件更新失败:resourceUrl不能为空");
        }
        if (ObjectUtil.isNull(seedUpdateFileProxyDto.getIs())){
            throw new FileUploadExp("文件更新失败:is不能为空");
        }
        ResourceUrlDividVo resourceUrlDividVo = getResourceUrlDividVo(seedUpdateFileProxyDto.getResourceUrl());
        SeedUpdateFileDto seedUpdateFileDto = new SeedUpdateFileDto();
        seedUpdateFileDto.setResourceId(resourceUrlDividVo.getResourceId());
        seedUpdateFileDto.setIs(seedUpdateFileProxyDto.getIs());

        SeedUploadFileVo seedUploadFileVo = resourceUrlDividVo.getFileContract().updateFile(seedUpdateFileDto);
        uploadFileRecorder.addUploadInfo(new RecordFileUniInfoDto(resourceUrlDividVo.getFileContract().getContractTypeInstance(),resourceUrlDividVo.getFileContract().getContractType(),seedUploadFileVo.getResourceId()));
        SeedUploadFileProxyVo seedUploadFileProxyVo = BeanUtil.copyProperties(seedUploadFileVo, SeedUploadFileProxyVo.class);
        seedUploadFileProxyVo.setContractType(resourceUrlDividVo.getFileContract().getContractType());
        seedUploadFileProxyVo.setContractTypeInstance(resourceUrlDividVo.getFileContract().getContractTypeInstance());
        return seedUploadFileProxyVo;
    }

    /**
     * 文件删除
     */
    public SeedUploadFileProxyVo deleteFile(SeedDeleteFileProxyDto seedDeleteFileProxyDto){
        if (ObjectUtil.isEmpty(seedDeleteFileProxyDto.getResourceUrl())){
            throw new FileUploadExp("文件删除失败:resourceUrl不能为空");
        }
        ResourceUrlDividVo resourceUrlDividVo = getResourceUrlDividVo(seedDeleteFileProxyDto.getResourceUrl());
        SeedDeleteFileDto seedDeleteFileDto = new SeedDeleteFileDto();
        seedDeleteFileDto.setResourceId(resourceUrlDividVo.getResourceId());
        SeedUploadFileVo seedUploadFileVo = resourceUrlDividVo.getFileContract().deleteFile(seedDeleteFileDto);
        SeedUploadFileProxyVo seedUploadFileProxyVo = BeanUtil.copyProperties(seedUploadFileVo, SeedUploadFileProxyVo.class);
        seedUploadFileProxyVo.setContractType(resourceUrlDividVo.getFileContract().getContractType());
        seedUploadFileProxyVo.setContractTypeInstance(resourceUrlDividVo.getFileContract().getContractTypeInstance());
        return seedUploadFileProxyVo;
    }


    /**
     * 分片上传 文件上传初始化
     */
    public SeedUploadChipFileInitProxyVo initUploadChipFile(SeedUploadChipFileInitDto seedUploadChipFileInitDto){
        if (seedUploadChipFileInitDto.getFileSize() < seedFileUploadProp.getChipFileSize() * 1024)
            throw new FileUploadExp("文件分片上传失败:文件太小无须分片");

        FileContract defaultContract = getFileContractByInstanceName(seedUploadChipFileInitDto.getContractTypeInstance());
        SeedUploadChipFileInitVo seedUploadChipFileInitVo = defaultContract.initUploadChipFile(seedUploadChipFileInitDto);

        uploadFileRecorder.addChipInfo(new RecordChipInfoDto(defaultContract.getContractTypeInstance(),defaultContract.getContractType(),seedUploadChipFileInitVo.getResourceId(),seedUploadChipFileInitVo.getChipSize()));

        //加密信息填充
        Map<String, Object> encodeMap = new HashMap<>();
        encodeMap.put("chipFileSize",seedUploadChipFileInitVo.getChipFileSize());
        encodeMap.put("chipSize",seedUploadChipFileInitVo.getChipSize());
        encodeMap.put("contractType", defaultContract.getContractType());
        encodeMap.put("contractTypeInstance", defaultContract.getContractTypeInstance());
        encodeMap.put("fileName",seedUploadChipFileInitDto.getFileName());
        encodeMap.put("extInfo",seedUploadChipFileInitVo.getExtInfo());
        SeedUploadChipFileInitProxyVo res = BeanUtil.copyProperties(seedUploadChipFileInitVo, SeedUploadChipFileInitProxyVo.class);
        res.setEncodeExtInfo(enCodeData(encodeMap));
        return res;
    }

    /**
     * 分片上传
     */
    public SeedUploadFileProxyVo uploadChipFile(SeedUploadChipFileProxyDto seedUploadChipFileProxyDto){
        if (ObjectUtil.isEmpty(seedUploadChipFileProxyDto.getResourceId())){
            throw new FileUploadExp("文件分片上传失败:resourceId不能为空");
        }
        if (ObjectUtil.isEmpty(seedUploadChipFileProxyDto.getIs())){
            throw new FileUploadExp("文件分片上传失败:is不能为空");
        }
        if (ObjectUtil.isNull(seedUploadChipFileProxyDto.getChipIndex())){
            throw new FileUploadExp("文件分片上传失败:chipIndex不能为空");
        }

        Map<String, Object> chipData = deCodeData(seedUploadChipFileProxyDto.getEncodeExtInfo());
        SeedUploadChipFileExtDto seedUploadChipFileExtDto = SeedUploadChipFileExtDto.createSeedUploadChipFileExtDto(chipData);
        FileContract defaultContract = getFileContractByInstanceName(seedUploadChipFileExtDto.getContractTypeInstance());
        if (!defaultContract.getContractTypeInstance().equals(seedUploadChipFileExtDto.getContractTypeInstance())){
            throw new ServiceExp("文件安全异常:类型不一致");
        }
        if (!(seedUploadChipFileProxyDto.getChipIndex() < seedUploadChipFileExtDto.getChipSize() && ObjectUtil.isNotNull(seedUploadChipFileProxyDto.getIs()))){
            throw new ServiceExp("文件安全异常:安全参数校验失败");
        }
        SeedUploadFileVo seedUploadFileVo = defaultContract.uploadChipFile(seedUploadChipFileProxyDto, seedUploadChipFileExtDto);
        uploadFileRecorder.addChipUploadInfo(new RecordChipUploadInfoDto(defaultContract.getContractTypeInstance(),defaultContract.getContractType(),seedUploadFileVo.getResourceId(),seedUploadChipFileProxyDto.getChipIndex()));
        SeedUploadFileProxyVo seedUploadFileProxyVo = BeanUtil.copyProperties(seedUploadFileVo, SeedUploadFileProxyVo.class);
        seedUploadFileProxyVo.setContractType(defaultContract.getContractType());
        seedUploadFileProxyVo.setContractTypeInstance(defaultContract.getContractTypeInstance());
        return seedUploadFileProxyVo;
    }

    /**
     * 上传文件合并
     */
    public SeedUploadFileProxyVo mergeChipFile(MergeChipFileProxyDto mergeChipFileProxyDto){
        Map<String, Object> chipData = deCodeData(mergeChipFileProxyDto.getEncodeExtInfo());
        SeedUploadChipFileExtDto seedUploadChipFileExtDto = SeedUploadChipFileExtDto.createSeedUploadChipFileExtDto(chipData);
        if (!seedUploadChipFileExtDto.getCanMergeFlag()){
            throw new ServiceExp("文件合并异常:分片上传需要校验");
        }
        FileContract defaultContract = getFileContractByInstanceName(seedUploadChipFileExtDto.getContractTypeInstance());

        SeedUploadFileVo seedUploadFileVo = defaultContract.mergeChipFile(mergeChipFileProxyDto, seedUploadChipFileExtDto);
        uploadFileRecorder.addUploadInfo(new RecordFileUniInfoDto(defaultContract.getContractTypeInstance(),defaultContract.getContractType(),seedUploadFileVo.getResourceId()));
        SeedUploadFileProxyVo seedUploadFileProxyVo = BeanUtil.copyProperties(seedUploadFileVo, SeedUploadFileProxyVo.class);
        seedUploadFileProxyVo.setContractType(defaultContract.getContractType());
        seedUploadFileProxyVo.setContractTypeInstance(defaultContract.getContractTypeInstance());
        return seedUploadFileProxyVo;
    }

    /**
     * 文件上传检查
     */
    public SeedCheckChipFileProxyVo checkChipFile(CheckChipFileProxyDto checkChipFileProxyDto){
        Map<String, Object> chipData = deCodeData(checkChipFileProxyDto.getEncodeExtInfo());
        SeedUploadChipFileExtDto seedUploadChipFileExtDto = SeedUploadChipFileExtDto.createSeedUploadChipFileExtDto(chipData);
        if (ObjectUtil.isEmpty(checkChipFileProxyDto.getResourceId())){
            throw new ServiceExp("文件分片检查失败:resourceId不能为空");
        }
        if (ObjectUtil.isNull(seedUploadChipFileExtDto.getChipSize())){
            throw new ServiceExp("文件分片检查失败:chipSize不能为空");
        }
        FileContract defaultContract = getFileContractByInstanceName(seedUploadChipFileExtDto.getContractTypeInstance());

        List<Integer> seedCheckChipFileVos = uploadFileRecorder.checkChipUploadInfo(new RecordFileUniInfoDto(defaultContract.getContractTypeInstance(), defaultContract.getContractType(), checkChipFileProxyDto.getResourceId()));
        SeedCheckChipFileProxyVo seedCheckChipFileProxyVo = new SeedCheckChipFileProxyVo();
        seedCheckChipFileProxyVo.setCheckChipFileVoList(seedCheckChipFileVos);
        boolean canMergeFlag = seedCheckChipFileVos.size() == 0;
        chipData.put("canMergeFlag",canMergeFlag);
        seedCheckChipFileProxyVo.setCanMergeFlag(canMergeFlag);
        seedCheckChipFileProxyVo.setEncodeData(enCodeData(chipData));
        seedCheckChipFileProxyVo.setContractType(defaultContract.getContractType());
        seedCheckChipFileProxyVo.setContractTypeInstance(defaultContract.getContractTypeInstance());
        return seedCheckChipFileProxyVo;
    }

    /**
     * 文件分片上传取消
     */
    public CancleChipFileProxyVo cancleChipFile(CancleChipFileProxyDto cancleChipFileProxyDto){
        Map<String, Object> chipData = deCodeData(cancleChipFileProxyDto.getEncodeExtInfo());
        SeedUploadChipFileExtDto seedUploadChipFileExtDto = SeedUploadChipFileExtDto.createSeedUploadChipFileExtDto(chipData);
        if (ObjectUtil.isEmpty(cancleChipFileProxyDto.getResourceId())){
            throw new ServiceExp("文件分片取消上传失败:resourceId不能为空");
        }
        if (ObjectUtil.isNull(seedUploadChipFileExtDto.getChipSize())){
            throw new ServiceExp("文件分片取消上传失败:chipSize不能为空");
        }
        FileContract defaultContract = getFileContractByInstanceName(seedUploadChipFileExtDto.getContractTypeInstance());

        CancleChipFileVo cancleChipFileVo = defaultContract.cancleChipFile(cancleChipFileProxyDto, seedUploadChipFileExtDto);
        uploadFileRecorder.removeChipUploadInfo(new RecordFileUniInfoDto(defaultContract.getContractTypeInstance(),defaultContract.getContractType(),cancleChipFileVo.getResourceId()));
        CancleChipFileProxyVo seedUploadFileProxyVo = BeanUtil.copyProperties(cancleChipFileVo, CancleChipFileProxyVo.class);
        seedUploadFileProxyVo.setContractType(defaultContract.getContractType());
        seedUploadFileProxyVo.setContractTypeInstance(defaultContract.getContractTypeInstance());
        return seedUploadFileProxyVo;
    }

    /**
     * 加密信息
     * @param data
     * @return
     */
    public String enCodeData(Map<String, Object> data) {
        try {
            return seedFileParamEncoder.enCodeData(JSONUtil.toJsonStr(data));
        } catch (Exception e) {
            throw new FileUploadExp("文件上传加密失败");
        }
    }

    /**
     * 解密信息
     * @param enCodeDataStr
     * @return
     */
    public Map<String, Object> deCodeData(String enCodeDataStr) {
        try {
            return JSONUtil.toBean(seedFileParamEncoder.deCodeData(enCodeDataStr), HashMap.class);
        } catch (Exception e) {
            throw new FileUploadExp("文件上传解密失败");
        }
    }
}